import random
import math
import sys
from tool import mns_math


class Position:
    def __init__(self, ship_count, x, y, min_distance: int = 1):
        self.num_points = ship_count
        self.center_x, self.center_y = x, y
        self.radius = self.num_points
        self.min_distance = min_distance

    def initial_solution(self):
        points = []
        for _ in range(self.num_points):
            # 生成随机的极坐标
            r = random.uniform(0, self.radius)
            theta = random.uniform(0, 2 * math.pi)
            # 将极坐标转换为笛卡尔坐标
            point_x = self.center_x + r * math.cos(theta)
            point_y = self.center_y + r * math.sin(theta)
            points.append((point_x, point_y))
        return points

    def distance(self, point1, point2):
        return math.sqrt((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2)

    def total_distance(self, points):
        total = 0
        for i in range(len(points) - 1):
            total += self.distance(points[i], points[i + 1])
        return total

    def acceptance_probability(self, old_cost, new_cost, temperature):
        if new_cost < old_cost:
            return 1.0
        else:
            return math.exp((old_cost - new_cost) / temperature)

    def anneal(self, initial_temperature = 1000, cooling_rate = 0.003,
               stopping_temperature = 0.1):
        points = self.initial_solution()
        current_solution = points[:]
        best_solution = points[:]
        temperature = initial_temperature
        while temperature > stopping_temperature:
            new_solution = current_solution[:]
            # 随机选择两个点进行交换
            swap_index1 = random.randint(0, len(new_solution) - 1)
            swap_index2 = random.randint(0, len(new_solution) - 1)
            new_solution[swap_index1], new_solution[swap_index2] = new_solution[swap_index2], new_solution[swap_index1]
            # 计算新解的成本
            current_cost = self.total_distance(current_solution)
            new_cost = self.total_distance(new_solution)
            # 根据Metropolis准则接受或拒绝新解
            if self.acceptance_probability(current_cost, new_cost, temperature) > random.random():
                current_solution = new_solution[:]
            # 更新最佳解
            if new_cost < self.total_distance(best_solution):
                best_solution = new_solution[:]
            # 降低温度
            temperature *= 1 - cooling_rate

        return best_solution

    def generate_pos(self):
        """使用退火算法生成船只位置"""
        while 1:
            result = self.anneal()
            min_dis = sys.float_info.max
            for i in range(len(result)):
                p1 = result[i]
                pi = mns_math.mns_round(p1[0])
                pj = mns_math.mns_round(p1[1])
                result[i] = pi, pj
                for j in range(i + 1, len(result)):
                    p2 = result[j]
                    dis = self.distance(p1, p2)
                    # print("点" + str(i) + "与点" + str(j) + "之间的距离为：" + str(dis))
                    if dis < min_dis:
                        min_dis = dis
            # print(min_dis)
            if min_dis >= 1:
                # print(result)
                return result


if __name__ == '__main__':
    # 示例用法
    num_points = 10
    center_x, center_y = 0, 0
    radius = num_points
    min_distance = 1
    pos = Position(num_points, center_x, center_y, min_distance)
    poss = pos.generate_pos()
